package ch.zhaw.skuh.turing.view;

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;

import ch.zhaw.skuh.turing.model.turingmaschine.TuringChar;

public class MaschineRulePanel extends JPanel {

	private TuringChar turingChar;
	private Object[] hashRules;
	private Component activeComp;

	private static final long serialVersionUID = 3540411182483585449L;

	public MaschineRulePanel(TuringChar turing) {
		this.turingChar = turing;
		// get possible combinations in alphabet
		List<char[]> combos = turingChar.getAlphabetCombinationsFiltered();

		// array for label/panels
		this.hashRules = new Object[turing.getMaxState()];
		for (int i = 0; i < turing.getMaxState(); i++) {
			hashRules[i] = new HashMap<String, Component>(combos.size());
		}
		

		// sanity disable more then 2'500 combos
		int comboTotal = combos.size() * combos.get(0).length;
		if (comboTotal <= 2500) {
			
			this.setBackground(Color.DARK_GRAY);

			GridLayout gridLayout = new GridLayout(0, combos.size() + 1);
			gridLayout.setHgap(1);
			gridLayout.setVgap(1);
			setLayout(gridLayout);

			// blank
			add(getHeaderLabel("\\"));
			// header line
			for (int i = 0; i < combos.size(); i++) {
				// String text = getComboText(combos[i]);
				add(getHeaderPanel(combos.get(i)));
			}
			// rows
			JLabel label;
			for (int state = 0; state < turingChar.getMaxState(); state++) {
				// row header
				label = getHeaderLabel(Integer.toString(state));
				// highlight accepted state
				if (turingChar.isAccepted(state)) {
					label.setBackground(Color.GREEN);
				}
				add(label);

				// store in hashmap
				@SuppressWarnings("unchecked")
				Map<String, Component> map = (Map<String, Component>) hashRules[state];

				// row data
				for (int i = 0; i < combos.size(); i++) {
					Component comp = getDataComponent(state, combos.get(i));
					add(comp);
					map.put(new String(combos.get(i)), comp);
				}

			}
			
		}
		
	}

	public void update() {
		// un-highlight previous
		if (activeComp != null) {
			activeComp.setBackground(Color.WHITE);
		}
		// show rule in turing-panel
		int state = turingChar.getMaschine().getState();
		char[] tapes = turingChar.getTapesAtCurrent();
		@SuppressWarnings("unchecked")
		Map<String, Component> map = (Map<String, Component>) hashRules[state];

		if (map.containsKey(new String(tapes))) {
			Component comp = map.get(new String(tapes));

			if (turingChar.getMaschine().hasRule()) {
				comp.setBackground(Color.YELLOW);
			} else if (turingChar.isAccepted(state)) {
				comp.setBackground(Color.GREEN);
			} else {
				comp.setBackground(Color.RED);
			}
			activeComp = comp;
		}

	}

	private JPanel getHeaderPanel(char[] text) {
		JPanel panel = new JPanel();
		panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
		for (int i = 0; i < text.length; i++) {
			panel.add(getHeaderLabel(Character.toString(text[i])));
		}
		panel.setBackground(Color.LIGHT_GRAY);
		//panel.setSize(panel.getMinimumSize());
		return panel;
	}

	private JLabel getHeaderLabel(String text) {
		JLabel label = new JLabel(text, JLabel.CENTER);
		label.setFont(new Font("Courier New", Font.BOLD, 9));
		label.setOpaque(true);
		label.setBackground(Color.LIGHT_GRAY);
		//label.setSize(label.getMinimumSize());
		return label;
	}

	private Component getDataComponent(int state, char[] combo) {
		Component comp;
		if (turingChar.hasRule(state, combo)) {
			comp = getDataPanel(state, combo);
			comp.setBackground(Color.WHITE);
		} else {
			comp = getDataLabel("--", true);
			comp.setBackground(Color.DARK_GRAY);
		}
		//comp.setSize(comp.getMinimumSize());
		return comp;
	}

	private JPanel getDataPanel(int state, char[] read) {
		JPanel panel = new JPanel();

		GridBagLayout gLayout = new GridBagLayout();
		GridBagConstraints gConstraints = new GridBagConstraints();

		// gConstraints.fill = GridBagConstraints.BOTH;
		gConstraints.weightx = 1.0;

		panel.setLayout(gLayout);

		JLabel jLabel;

		// state
		jLabel = getDataLabel(
				Integer.toString(turingChar.getRuleState(state, read)), false);
		// row end
		gConstraints.gridwidth = GridBagConstraints.REMAINDER; // end row
		gLayout.setConstraints(jLabel, gConstraints);
		panel.add(jLabel);
		char[] write = turingChar.getRuleChars(state, read);
		int[] move = turingChar.getRuleMoves(state, read);
		for (int i = 0; i < turingChar.getTapeCount(); i++) {
			// new char
			jLabel = getDataLabel(Character.toString(write[i]), false);
			// reset
			gConstraints.gridwidth = 1;
			gLayout.setConstraints(jLabel, gConstraints);
			panel.add(jLabel);
			// move
			jLabel = getDataLabel(Integer.toString(move[i]), false);
			// row end
			gConstraints.gridwidth = GridBagConstraints.REMAINDER; // end row
			gLayout.setConstraints(jLabel, gConstraints);
			panel.add(jLabel);
		}
		//panel.setSize(panel.getMinimumSize());
		return panel;
	}

	private JLabel getDataLabel(String text, boolean transparent) {
		JLabel label = new JLabel(text, JLabel.CENTER);
		label.setOpaque(transparent);
		label.setFont(new Font("Courier New", Font.PLAIN, 9));
		//label.setSize(label.getMinimumSize());
		return label;
	}

}
